package db_meta

import (
	db "engine/db"
	"servers/models/define"
	"servers/models/meta"
	"servers/models/protos/google/pb/rpc_protos"

	"gitee.com/ameise84/e3utils/str_conv"
	jsoniter "github.com/json-iterator/go"
	"gorm.io/gorm"
)

func init() {
	db.RegisterTableMetaFactory(AcPlayerFactory)
	db.RegisterTableMetaFactory(PlayerBetInGameFactory)
	db.RegisterTableMetaFactory(PlayerBetFactory)
	db.RegisterTableMetaFactory(PlayerScoreFactory)
	db.RegisterTableMetaFactory(PlayerBaseInfoFactory)
	db.RegisterTableMetaFactory(GameOfflineDataFactory)
}

func AcPlayerFactory() db.TableMeta {
	return &AcPlayer{}
}

type AcPlayer struct {
	UserID     define.UserIDType     `json:"id" form:"id" gorm:"primarykey;column:id"`              // 用户ID
	Account    string                `json:"account" form:"account" gorm:"column:account"`          // 账号
	Password   string                `json:"psw" form:"psw" gorm:"column:psw"`                      // 密码
	NickName   string                `json:"nickName" form:"nickName" gorm:"column:nick_name"`      // 名称
	BusinessID define.BusinessIDType `json:"bid" form:"bid" gorm:"column:bid"`                      // 商人ID
	ScoreType  define.ScoreType      `json:"score_type" form:"score_type" gorm:"column:score_type"` // 积分类型
	BagType    define.BagType        `json:"bag_type" form:"bag_type" gorm:"column:bag_type"`       // 钱包类型
	UserType   define.UserType       `json:"user_type" form:"user_type" gorm:"column:user_type"`    // 用户类型
	UserTag    define.UserTag        `json:"user_tag" form:"user_tag" gorm:"column:user_tag"`       // 用户标签
}

func (v *AcPlayer) BaseTableName() string {
	return v.TableName()
}

func (v *AcPlayer) TableName() string {
	return "ac_player"
}

func (v *AcPlayer) ID() string {
	return str_conv.ToString(v.UserID)
}

func (v *AcPlayer) MarshalBinary() (data []byte, err error) {
	return jsoniter.Marshal(v)
}

func (v *AcPlayer) UnmarshalBinary(data []byte) error {
	return jsoniter.Unmarshal(data, v)
}

func (v *AcPlayer) WhereByAccountAndBid() string {
	return "account = ? AND bid = ?"
}

func (v *AcPlayer) ToPBMeta(meta *rpc_protos.AccountMeta) {
	meta.UserID = v.UserID
	meta.Account = v.Account
	meta.Password = v.Password
	meta.NickName = v.NickName
	meta.BusinessID = v.BusinessID
	meta.ScoreType = v.ScoreType
	meta.BagType = v.BagType
	meta.UserType = v.UserType
	meta.UserTag = v.UserTag
}

func (v *AcPlayer) FromPBMeta(meta *rpc_protos.AccountMeta) {
	v.UserID = meta.UserID
	v.Account = meta.Account
	v.Password = meta.Password
	v.NickName = meta.NickName
	v.BusinessID = meta.BusinessID
	v.ScoreType = meta.ScoreType
	v.BagType = meta.BagType
	v.UserType = meta.UserType
	v.UserTag = meta.UserTag
}

func PlayerBetInGameFactory() db.TableMeta {
	return &StatPlayerBetInGame{}
}

type StatPlayerBetInGame struct {
	GameKindID define.GameKind `gorm:"-"`
	StatPlayerBet
}

func (v *StatPlayerBetInGame) Init() {
	v.GameKindID = 0
	v.StatPlayerBet.Init()
}

func (v *StatPlayerBetInGame) Reset(info *AcPlayer, gameKind uint32) {
	v.Init()
	v.GameKindID = gameKind
	v.StatPlayerBet.Reset(info)
}

func (v *StatPlayerBetInGame) BaseTableName() string {
	return "stat_player_bet_in_"
}

func (v *StatPlayerBetInGame) TableName() string {
	return v.BaseTableName() + str_conv.ToString(v.GameKindID)
}

func PlayerBetFactory() db.TableMeta {
	return &StatPlayerBet{}
}

type StatPlayerBet struct {
	UserID           define.UserIDType     `json:"id" form:"id" gorm:"primarykey;column:id;autoIncrement:false"` // 用户ID
	BusinessID       define.BusinessIDType `json:"bid" form:"bid" gorm:"column:bid"`                             // 商人ID
	ScoreType        define.ScoreType      `json:"score_type" form:"score_type" gorm:"column:score_type"`
	TotalBetScore    define.GameScore      `json:"total_bet_score" form:"total_bet_score" gorm:"column:total_bet_score"`
	TotalRewardScore define.GameScore      `json:"total_reward_score" form:"total_reward_score" gorm:"column:total_reward_score"`
	TotalRound       int64                 `json:"total_round" form:"total_round" gorm:"column:total_round"`
	TodayBetScore    define.GameScore      `json:"today_bet_score" form:"today_bet_score" gorm:"column:today_bet_score"`
	TodayRewardScore define.GameScore      `json:"today_reward_score" form:"today_reward_score" gorm:"column:today_reward_score"`
	TodayRound       int64                 `json:"today_round" form:"today_round" gorm:"column:today_round"`
	LastBetTime      int64                 `json:"last_bet_time" form:"last_bet_time" gorm:"column:last_bet_time"`
	FirstBetTime     int64                 `json:"first_bet_time" form:"first_bet_time" gorm:"column:first_bet_time"`
	LastLoginTime    int64                 `json:"last_login_time" form:"last_login_time" gorm:"column:last_login_time"`
}

func (v *StatPlayerBet) Init() {
	v.UserID = 0
	v.BusinessID = 0
	v.ScoreType = 0
	v.TotalBetScore = 0
	v.TotalRewardScore = 0
	v.TotalRound = 0
	v.TodayBetScore = 0
	v.TodayRewardScore = 0
	v.TodayRound = 0
	v.LastBetTime = 0
	v.FirstBetTime = 0
	v.LastLoginTime = 0
}

func (v *StatPlayerBet) Reset(info *AcPlayer) {
	v.Init()
	v.UserID = info.UserID
	v.BusinessID = info.BusinessID
	v.ScoreType = info.ScoreType
}

func (v *StatPlayerBet) BaseTableName() string {
	return v.TableName()
}

func (v *StatPlayerBet) TableName() string {
	return "stat_player_bet"
}

func (v *StatPlayerBet) ID() string {
	return str_conv.ToString(v.UserID)
}

func (v *StatPlayerBet) MarshalBinary() (data []byte, err error) {
	return jsoniter.Marshal(v)
}

func (v *StatPlayerBet) UnmarshalBinary(data []byte) error {
	return jsoniter.Unmarshal(data, v)
}

func PlayerScoreFactory() db.TableMeta {
	return &StatPlayerScore{}
}

type StatPlayerScore struct {
	UserID         define.UserIDType `json:"id" form:"id" gorm:"primarykey;column:id"`
	Score          define.GameScore  `json:"score" form:"score" gorm:"column:score"`
	LockScore      define.GameScore  `json:"lock_score" form:"lock_score" gorm:"column:lock_score"`
	CtrlTickOut    define.GameScore  `json:"ctrl_tick_out" form:"ctrl_tick_out" gorm:"column:ctrl_tick_out"`
	meta.CtrlInfos `json:"ctrl_infos" gorm:"-"`
	CtrlInfoJs     string `json:"-" form:"ctrl_js" gorm:"column:ctrl_js"`
}

func (v *StatPlayerScore) Init() {
	v.UserID = 0
	v.Score = 0
	v.LockScore = 0
	v.CtrlTickOut = 0
	v.RestCtrlList()
	v.CtrlInfoJs = ""
}

func (v *StatPlayerScore) Reset(info *AcPlayer) {
	v.Init()
	v.UserID = info.UserID
}

func (v *StatPlayerScore) BaseTableName() string {
	return v.TableName()
}

func (v *StatPlayerScore) TableName() string {
	return "stat_player_score"
}

func (v *StatPlayerScore) ID() string {
	return str_conv.ToString(v.UserID)
}

func (v *StatPlayerScore) MarshalBinary() (data []byte, err error) {
	return jsoniter.Marshal(v)
}

func (v *StatPlayerScore) UnmarshalBinary(data []byte) error {
	return jsoniter.Unmarshal(data, v)
}

func (v *StatPlayerScore) BeforeSave(db *gorm.DB) (err error) {
	v.CtrlInfoJs = v.CtrlInfos.ToJsonStr()
	return nil
}

func (v *StatPlayerScore) AfterFind(db *gorm.DB) error {
	v.CtrlInfos.FromJsonStr(v.CtrlInfoJs)
	return nil
}

func (v *StatPlayerScore) ToPBMeta(meta *rpc_protos.PlayerScoreMeta) {
	meta.UserID = v.UserID
	meta.Score = v.Score
	meta.LockScore = v.LockScore
	meta.CtrlTickOut = v.CtrlTickOut
	meta.Ctrl = make([]*rpc_protos.DotCtrlMeta, len(v.Ctrl))
	for i := range v.Ctrl {
		meta.Ctrl[i] = &rpc_protos.DotCtrlMeta{
			Level: v.Ctrl[i].Level,
			Score: v.Ctrl[i].Score,
		}
	}
}

func (v *StatPlayerScore) FromPBMeta(meta *rpc_protos.PlayerScoreMeta) {
	v.UserID = meta.UserID
	v.Score = meta.Score
	v.LockScore = meta.LockScore
	v.CtrlTickOut = meta.CtrlTickOut
	v.SetCtrlInfos(meta.Ctrl)
}

func (v *StatPlayerScore) RestCtrlList() {
	if v.Ctrl == nil {
		v.Ctrl = make([]meta.CtrlMeta, 1)
	}
	v.Ctrl = v.Ctrl[:1]
	v.Ctrl[0].Level = 0
	v.Ctrl[0].Score = 0
}

func (v *StatPlayerScore) SetCtrlInfos(Ctrl []*rpc_protos.DotCtrlMeta) {
	if len(Ctrl) == 0 {
		if cap(v.Ctrl) == 0 {
			v.Ctrl = make([]meta.CtrlMeta, 1)
		}
		v.Ctrl[0].Level = 0
		v.Ctrl[0].Score = 0
		v.Ctrl = v.Ctrl[:1]
	} else {
		// logger.TracePrintf("SetCtrlInfos: %v", Ctrl)
		if cap(v.Ctrl) < len(Ctrl) {
			v.Ctrl = make([]meta.CtrlMeta, len(Ctrl))
		}
		v.Ctrl = v.Ctrl[:len(Ctrl)]
		for i, value := range Ctrl {
			v.Ctrl[i].Level = value.Level
			v.Ctrl[i].Score = value.Score
		}
	}
	v.CtrlTickOut = 0
}

func (v *StatPlayerScore) UpdateDotCtrl(score int64) {
	if score != 0 && v.Ctrl[0].Level != 0 {
		if v.Ctrl[0].Level > 0 {
			v.CtrlTickOut -= score
		} else {
			v.CtrlTickOut += score
		}
		// logger.TracePrintf("UpdateDotCtrl: %v %v  %v", v.Ctrl, v.CtrlTickOut, score)
		if v.CtrlTickOut >= v.Ctrl[0].Score {
			v.CtrlTickOut = 0
			if len(v.Ctrl) == 1 {
				v.Ctrl[0].Level = 0
				v.Ctrl[0].Score = 0
			} else {
				v.Ctrl = v.Ctrl[1:]
			}
		}
	}
}

func PlayerBaseInfoFactory() db.TableMeta {
	return &StatPlayerBaseInfo{}
}

type StatPlayerBaseInfo struct {
	UserID        define.UserIDType `json:"id" form:"id" gorm:"primarykey;column:id"`
	SignUpTime    int64             `json:"sign_up_time" form:"sign_up_time" gorm:"column:sign_up_time"`
	BringInScore  define.GameScore  `json:"bring_in_score" form:"bring_in_score" gorm:"column:bring_in_score"`
	BringOutScore define.GameScore  `json:"bring_out_score" form:"bring_out_score" gorm:"column:bring_out_score"`
	RechargeScore define.GameScore  `json:"recharge_score" form:"recharge_score" gorm:"column:recharge_score"`
}

func (v *StatPlayerBaseInfo) Init() {
	v.UserID = 0
	v.SignUpTime = 0
	v.BringInScore = 0
	v.BringOutScore = 0
	v.RechargeScore = 0
}

func (v *StatPlayerBaseInfo) Reset(info *AcPlayer) {
	v.Init()
	v.UserID = info.UserID
}

func (v *StatPlayerBaseInfo) BaseTableName() string {
	return v.TableName()
}

func (v *StatPlayerBaseInfo) TableName() string {
	return "stat_player_base_info"
}

func (v *StatPlayerBaseInfo) ID() string {
	return str_conv.ToString(v.UserID)
}

func (v *StatPlayerBaseInfo) MarshalBinary() (data []byte, err error) {
	return jsoniter.Marshal(v)
}

func (v *StatPlayerBaseInfo) UnmarshalBinary(data []byte) error {
	return jsoniter.Unmarshal(data, v)
}

func GameOfflineDataFactory() db.TableMeta {
	return &GameOfflineData{}
}

type GameOfflineData struct {
	GameKind   define.GameKind   `json:"game_kind" form:"game_kind" gorm:"-"`
	UserID     define.UserIDType `json:"id" form:"id" gorm:"primarykey;column:id"` // 平台ID
	PlayerData []byte            `json:"player_data" form:"player_data" gorm:"column:player_data;type:blob"`
	FrameData  []byte            `json:"frame_data" form:"frame_data" gorm:"column:frame_data;type:blob"`
}

func (v *GameOfflineData) BaseTableName() string {
	return "stat_game_offline"
}

func (v *GameOfflineData) TableName() string {
	return v.BaseTableName() + "_" + str_conv.ToString(v.GameKind)
}

func (v *GameOfflineData) ID() string {
	return str_conv.ToString(v.UserID)
}

func (v *GameOfflineData) MarshalBinary() (data []byte, err error) {
	return jsoniter.Marshal(v)
}

func (v *GameOfflineData) UnmarshalBinary(data []byte) error {
	return jsoniter.Unmarshal(data, v)
}
